/**
 * 请求队列管理器
 * 用于在离线时存储请求，在线时批量发送
 */

import { networkStatus } from './networkStatus';

// 请求优先级枚举
const RequestPriority = {
    HIGH: 3, // 高优先级
    MEDIUM: 2, // 中优先级
    LOW: 1 // 低优先级
};

// 请求状态枚举
const RequestStatus = {
    PENDING: 'pending', // 等待处理
    PROCESSING: 'processing', // 正在处理
    COMPLETED: 'completed', // 处理完成
    FAILED: 'failed', // 处理失败
    RETRYING: 'retrying' // 正在重试
};

class RequestQueue {
    constructor() {
        this.queue = [];
        this.isProcessing = false;
        this.maxRetries = 3; // 最大重试次数
        this.storageKey = 'offline-request-queue';
        this.lastRequestId = null;
        this.debounceTimer = null;
        this.debounceDelay = 1000;
        this.dbName = 'OfflineRequestQueueDB';
        this.dbVersion = 1;
        this.storeName = 'requests';
        this.db = null;
        this.baseDelay = 1000; // 基础延迟时间（毫秒）
        this.maxDelay = 30000; // 最大延迟时间（毫秒）

        // 状态变更监听器
        this.statusListeners = new Set();

        // 初始化 IndexedDB
        this.initIndexedDB();

        // 从本地存储加载队列
        this.loadQueue();

        // 监听网络状态变化
        this.removeNetworkListener = networkStatus.addListener(this.handleNetworkChange.bind(this));

        // 定期保存队列到本地存储
        setInterval(() => this.saveQueue(), 5000);
    }

    /**
     * 添加状态变更监听器
     * @param {Function} listener - 监听器函数
     * @returns {Function} - 移除监听器的函数
     */
    addStatusListener(listener) {
        this.statusListeners.add(listener);
        return () => this.statusListeners.delete(listener);
    }

    /**
     * 触发状态变更事件
     * @param {Object} request - 请求对象
     * @param {string} oldStatus - 旧状态
     * @param {string} newStatus - 新状态
     */
    notifyStatusChange(request, oldStatus, newStatus) {
        this.statusListeners.forEach(listener => {
            try {
                listener(request, oldStatus, newStatus);
            } catch (error) {
                console.error('状态变更监听器执行出错:', error);
            }
        });
    }

    /**
     * 更新请求状态
     * @param {Object} request - 请求对象
     * @param {string} newStatus - 新状态
     */
    updateRequestStatus(request, newStatus) {
        if (!request || !Object.values(RequestStatus).includes(newStatus)) {
            return;
        }

        const oldStatus = request.status;
        request.status = newStatus;

        // 触发状态变更事件
        this.notifyStatusChange(request, oldStatus, newStatus);

        // 保存状态变更
        this.saveQueue();
    }

    /**
     * 获取队列状态统计
     * @returns {Object} - 状态统计信息
     */
    getQueueStatusStats() {
        return {
            total: this.queue.length,
            pending: this.queue.filter(r => r.status === RequestStatus.PENDING).length,
            processing: this.queue.filter(r => r.status === RequestStatus.PROCESSING).length,
            completed: this.queue.filter(r => r.status === RequestStatus.COMPLETED).length,
            failed: this.queue.filter(r => r.status === RequestStatus.FAILED).length,
            retrying: this.queue.filter(r => r.status === RequestStatus.RETRYING).length
        };
    }

    /**
     * 初始化 IndexedDB
     */
    initIndexedDB() {
        return new Promise((resolve, reject) => {
            const request = indexedDB.open(this.dbName, this.dbVersion);

            request.onerror = () => {
                console.error('IndexedDB 初始化失败');
                reject(request.error);
            };

            request.onsuccess = (event) => {
                this.db = event.target.result;
                console.log('IndexedDB 初始化成功');
                resolve();
            };

            request.onupgradeneeded = (event) => {
                const db = event.target.result;
                if (!db.objectStoreNames.contains(this.storeName)) {
                    db.createObjectStore(this.storeName, { keyPath: 'id' });
                }
            };
        });
    }

    /**
     * 从本地存储加载队列
     */
    async loadQueue() {
        try {
            // 首先尝试从 IndexedDB 加载
            if (this.db) {
                const transaction = this.db.transaction([this.storeName], 'readonly');
                const store = transaction.objectStore(this.storeName);
                const request = store.getAll();

                request.onsuccess = (event) => {
                    const savedQueue = event.target.result;
                    if (savedQueue && savedQueue.length > 0) {
                        this.queue = savedQueue.filter(request =>
                            request &&
                            request.fn &&
                            request.args !== undefined &&
                            request.timestamp
                        );
                        console.log(`从 IndexedDB 加载了 ${this.queue.length} 个离线请求`);
                        return;
                    }
                };
            }

            // 如果 IndexedDB 没有数据，尝试从 localStorage 加载
            const savedQueue = localStorage.getItem(this.storageKey);
            if (savedQueue) {
                const parsedQueue = JSON.parse(savedQueue);
                this.queue = parsedQueue.filter(request =>
                    request &&
                    request.fn &&
                    request.args !== undefined &&
                    request.timestamp
                );
                console.log(`从 localStorage 加载了 ${this.queue.length} 个离线请求`);

                // 将数据同步到 IndexedDB
                if (this.db) {
                    const transaction = this.db.transaction([this.storeName], 'readwrite');
                    const store = transaction.objectStore(this.storeName);
                    this.queue.forEach(request => {
                        store.put(request);
                    });
                }
            }
        } catch (error) {
            console.error('加载离线队列失败:', error);
            this.queue = [];
        }
    }

    /**
     * 保存队列到本地存储
     */
    async saveQueue() {
        try {
            // 过滤掉无效的请求
            const validQueue = this.queue.filter(request =>
                request &&
                request.fn &&
                request.args !== undefined &&
                request.timestamp
            );

            // 只保存必要的请求信息
            const queueToSave = validQueue.map(request => ({
                id: request.id,
                args: request.args,
                timestamp: request.timestamp,
                status: request.status,
                retries: request.retries
            }));

            // 保存到 localStorage
            localStorage.setItem(this.storageKey, JSON.stringify(queueToSave));

            // 保存到 IndexedDB
            if (this.db) {
                const transaction = this.db.transaction([this.storeName], 'readwrite');
                const store = transaction.objectStore(this.storeName);

                // 先清空存储
                await new Promise((resolve, reject) => {
                    const clearRequest = store.clear();
                    clearRequest.onsuccess = resolve;
                    clearRequest.onerror = reject;
                });

                // 保存新数据
                await Promise.all(queueToSave.map(request =>
                    new Promise((resolve, reject) => {
                        const request = store.put(request);
                        request.onsuccess = resolve;
                        request.onerror = reject;
                    })
                ));
            }
        } catch (error) {
            console.error('保存离线队列失败:', error);
        }
    }

    /**
     * 处理网络状态变化
     * @param {boolean} isOnline - 是否在线
     */
    handleNetworkChange(isOnline) {
        if (isOnline && this.queue.length > 0) {
            console.log(`网络已恢复，开始处理队列中的 ${this.queue.length} 个请求`);
            this.processQueue();
        }
    }

    /**
     * 添加请求到队列
     * @param {Function} requestFn - 请求函数
     * @param {Array} args - 请求参数
     * @param {Object} options - 选项
     * @returns {Promise} - 返回Promise
     */
    async add(requestFn, args = [], options = {}) {
        if (!requestFn || typeof requestFn !== 'function') {
            throw new Error('无效的请求函数');
        }

        const request = {
            id: Date.now() + Math.random().toString(36).substr(2, 9),
            fn: requestFn,
            args: args || [],
            options: {
                ...options,
                priority: options.priority || RequestPriority.MEDIUM, // 默认中等优先级
                timestamp: Date.now()
            },
            retries: 0,
            timestamp: Date.now(),
            status: 'pending'
        };

        // 如果在线，直接执行请求
        if (networkStatus.isOnline()) {
            try {
                const result = await this.executeRequest(request);
                return result;
            } catch (error) {
                // 如果请求失败且网络仍然在线，直接抛出错误
                if (networkStatus.isOnline()) {
                    throw error;
                }
                // 如果请求失败时网络已离线，将请求添加到队列
                console.log('请求失败时网络已离线，将请求添加到队列');
                this.addToQueue(request);
                throw error;
            }
        }

        // 如果离线，使用防抖添加请求
        console.log('网络离线，请求已加入队列');
        this.addToQueue(request);

        // 返回一个Promise，当请求完成时resolve
        return new Promise((resolve, reject) => {
            request.resolve = resolve;
            request.reject = reject;
        });
    }

    /**
     * 使用防抖添加请求到队列
     * @param {Object} request - 请求对象
     */
    addToQueue(request) {
        // 清除之前的定时器
        if (this.debounceTimer) {
            clearTimeout(this.debounceTimer);
        }

        // 记录当前请求ID
        this.lastRequestId = request.id;

        // 设置新的定时器
        this.debounceTimer = setTimeout(() => {
            // 如果这个请求是最后一个请求，则添加到队列
            if (request.id === this.lastRequestId) {
                // 移除之前的相同类型的请求
                this.queue = this.queue.filter(r => r.fn !== request.fn);
                this.queue.push(request);

                // 按优先级和时间戳排序
                this.sortQueue();

                this.saveQueue();
            }
        }, this.debounceDelay);
    }

    /**
     * 对队列进行排序
     * 优先级高的先处理，同优先级的按时间戳排序
     */
    sortQueue() {
        this.queue.sort((a, b) => {
            // 首先按优先级排序
            const priorityDiff = b.options.priority - a.options.priority;
            if (priorityDiff !== 0) {
                return priorityDiff;
            }
            // 同优先级按时间戳排序
            return a.timestamp - b.timestamp;
        });
    }

    /**
     * 计算指数退避延迟时间
     * @param {number} retryCount - 当前重试次数
     * @returns {number} - 延迟时间（毫秒）
     */
    calculateBackoffDelay(retryCount) {
        // 使用指数退避算法计算延迟时间
        // 公式：delay = min(baseDelay * 2^retryCount, maxDelay)
        const delay = Math.min(
            this.baseDelay * Math.pow(2, retryCount),
            this.maxDelay
        );

        // 添加随机抖动，避免多个请求同时重试
        const jitter = Math.random() * 0.1 * delay; // 10% 的随机抖动
        return delay + jitter;
    }

    /**
     * 处理队列中的请求
     */
    async processQueue() {
        if (this.isProcessing || this.queue.length === 0 || !networkStatus.isOnline()) {
            return;
        }

        this.isProcessing = true;
        console.log(`开始处理队列，剩余 ${this.queue.length} 个请求`);

        try {
            // 按优先级和时间戳排序
            this.sortQueue();

            // 创建一个Map来存储每种类型的最新请求
            const latestRequests = new Map();

            // 遍历队列，只保留每种类型的最新请求
            this.queue.forEach(request => {
                if (!request || !request.fn) {
                    console.warn('发现无效请求，已移除');
                    return;
                }

                // 使用请求函数的字符串表示作为键
                const requestKey = request.fn.toString();
                const existingRequest = latestRequests.get(requestKey);

                // 如果已存在相同类型的请求，保留优先级高的或时间戳新的
                if (!existingRequest ||
                    request.options.priority > existingRequest.options.priority ||
                    (request.options.priority === existingRequest.options.priority &&
                        request.timestamp > existingRequest.timestamp)) {
                    latestRequests.set(requestKey, request);
                }
            });

            // 更新队列，只保留最新的请求
            this.queue = Array.from(latestRequests.values());

            // 重新排序
            this.sortQueue();

            while (this.queue.length > 0 && networkStatus.isOnline()) {
                const request = this.queue[0];
                if (!request || !request.fn) {
                    console.warn('发现无效请求，已移除');
                    this.queue.shift();
                    continue;
                }

                try {
                    // 更新状态为处理中
                    this.updateRequestStatus(request, RequestStatus.PROCESSING);

                    const result = await this.executeRequest(request);

                    // 更新状态为完成
                    this.updateRequestStatus(request, RequestStatus.COMPLETED);
                    request.resolve(result);

                    this.queue.shift(); // 移除已处理的请求
                    this.saveQueue(); // 保存更新后的队列
                } catch (error) {
                    if (request.retries < this.maxRetries) {
                        request.retries++;

                        // 更新状态为重试中
                        this.updateRequestStatus(request, RequestStatus.RETRYING);

                        // 计算退避延迟时间
                        const backoffDelay = this.calculateBackoffDelay(request.retries);
                        console.log(
                            `请求失败，将在 ${backoffDelay}ms 后重试 (${request.retries}/${this.maxRetries}):`,
                            error
                        );

                        // 等待退避时间后重试
                        await new Promise((resolve) => setTimeout(resolve, backoffDelay));
                    } else {
                        // 更新状态为失败
                        this.updateRequestStatus(request, RequestStatus.FAILED);
                        console.error('请求失败，已达到最大重试次数:', error);
                        request.reject(error);
                        this.queue.shift(); // 移除失败的请求
                        this.saveQueue(); // 保存更新后的队列
                    }
                }
            }
        } finally {
            this.isProcessing = false;

            // 如果队列中还有请求，继续处理
            if (this.queue.length > 0 && networkStatus.isOnline()) {
                setTimeout(() => this.processQueue(), 100);
            }
        }
    }

    /**
     * 执行单个请求
     * @param {Object} request - 请求对象
     * @returns {Promise} - 返回Promise
     */
    async executeRequest(request) {
        if (!request || !request.fn || typeof request.fn !== 'function') {
            throw new Error('无效的请求对象');
        }

        console.log(`执行请求: ${request.id}`);
        return request.fn(...request.args);
    }

    /**
     * 获取队列长度
     * @returns {number} - 队列长度
     */
    getQueueLength() {
        return this.queue.length;
    }

    /**
     * 获取队列状态
     * @returns {Object} - 队列状态信息
     */
    getQueueStatus() {
        return {
            total: this.queue.length,
            pending: this.queue.filter((r) => r.status === 'pending').length,
            processing: this.queue.filter((r) => r.status === 'processing').length,
            completed: this.queue.filter((r) => r.status === 'completed').length,
            failed: this.queue.filter((r) => r.status === 'failed').length,
            retrying: this.queue.filter((r) => r.status === 'retrying').length
        };
    }

    /**
     * 清空队列
     */
    clearQueue() {
        this.queue = [];
        localStorage.removeItem(this.storageKey);
    }

    /**
     * 销毁实例
     */
    destroy() {
        this.removeNetworkListener();
        this.clearQueue();
        if (this.debounceTimer) {
            clearTimeout(this.debounceTimer);
        }
    }
}

// 创建单例实例
const requestQueue = new RequestQueue();

export default requestQueue;